﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace HSFB.Console
{
    public static class Menu
    {
        private static List<Option> _options { get; set; }

        static Menu()
        {
            //Creates menu options
            _options = new List<Option>() 
            { 
                new Option("1-100", "Default", "System.Console", "Default"),
                new Option("-100-100", "Default", "System.Console", "Default_Range"),
                new Option("1-100", "User Input", "System.Console", "Default_Labels"),
                new Option("1-100", "Custom hardcoded", "TraceListener Log file", "Trace_LogFile"),
                new Option("1-100", "Default", "TraceListener Console", "Trace_Console"),
                new Option("1-100", "Default", "String Collection Console", "Trace_Collection"),
                new Option("1-100", "Default", "StringWriter Console", "Trace_TextWriter"),
                new Option("1-100", "Default", "MemoryStream Console", "Default_Stream"),
                new Option("1-100", "Default", "FBWriter Console", "Default_FBWriter"),
                new Option("Quit", "Exit")
            };
        }

        /// <summary>
        /// Renders menu options and waits for user selection
        /// </summary>
        public static void Render()
        {
            System.Console.Clear();

            //Render options
            var i = 1;
            _options.ForEach(option =>
                System.Console.WriteLine(
                    string.Format("{0} => {1}", i++, option.ToString())));

            System.Console.WriteLine("Select your option");

            //Validate user input
            var isValid = false;
            do
            {
                isValid = IsValidInput();
            } while (!isValid);

        }

        /// <summary>
        /// Validates menu selection is valid
        /// </summary>
        /// <returns></returns>
        static bool IsValidInput()
        {
            var isValid = false;
            var input = System.Console.ReadLine();
        
            var index = -1;
            //validate integer
            isValid = int.TryParse(input, out index);
            if (isValid)
            {
                //Validate option exists
               var option = _options.ElementAtOrDefault(index - 1);
               isValid = option != null;

               if (isValid)
                   Execute(option);
            }

            return isValid;
        }

        /// <summary>
        /// Executes selected option
        /// </summary>
        /// <param name="option"></param>
        static void Execute(Option option)
        {
            System.Console.Clear();
            System.Console.Write("Executing {0}", option.ToString());

            //Invoke method thru reflection
            typeof(Test).InvokeMember(option.Function, BindingFlags.Default | BindingFlags.InvokeMethod, null, null, new object[] { option.ToString() });

            System.Console.WriteLine("Enter to return to main menu");
            System.Console.ReadLine();
            Render();

        }

        /// <summary>
        /// Option class to hold menu option properties
        /// </summary>
        class Option
        {
            public Option(string custom, string function)
            {
                this.Custom = custom;
                this.Function = function;
            }

            public Option(string range, string labels, string output, string function)
            {
                this.Range = range;
                this.Labels = labels;
                this.Output = output;
                this.Function = function;
            }

            public string Range { get; set; }
            public string Labels { get; set; }
            public string Output { get; set; }
            public string Custom { get; set; }
            public string Function { get; set; }

            /// <summary>
            /// Override default to string to return custom label
            /// </summary>
            /// <returns></returns>
            public override string ToString()
            {
                var option = string.Empty;

                if (string.IsNullOrEmpty(Custom))
                    option = string.Format("Range: {0} Labels: {1} Output: {2}",
                      Range, Labels, Output);
                else
                    option = string.Format("{0}", Custom);


                return option;
            }
        }
    }
}
